package mybitcoin

import (
	"github.com/boltdb/bolt"
	"log"
	"bytes"
	"fmt"
)

/*
3.区块链
 */
type BlockChain struct {
	//Blocks []*Block
	BoltDB  *bolt.DB
	//因为数据库里没有排序，必须告诉新的block前一个块的HASH
	lastHash []byte
}

/*
创建区块链
 */
func NewBlockChain() *BlockChain {
	//创世块
	genesisBlock := GenesisBlock()
	//最后的HASH
	var lastHash []byte
	//保存数据库
	db, err := bolt.Open("blockchainDB.db", 0600, nil)
	if err!=nil {
		log.Panic("bolt.Open...err")
	}
	//defer db.Close()这里不能关，否则添加区块的时候报错

	db.Update(func(tx *bolt.Tx) error {
		//查找抽屉
		bucket:=tx.Bucket([]byte("blockBucket"))
		if bucket==nil{
			//没有抽屉，创建
			bucket, err = tx.CreateBucket([]byte("blockBucket"))
			if err!=nil {
				log.Panic("createBucket err...")
			}
			bucket.Put(genesisBlock.CurrentHash,genesisBlock.Serialize())
			bucket.Put([]byte("lastHashKey"),genesisBlock.CurrentHash)
			lastHash=genesisBlock.CurrentHash
		}else{
			//有抽屉,读出最后一个key
			lastHash = bucket.Get([]byte("lastHashKey"))
		}


		return nil
	})


	return &BlockChain{
		db,lastHash,
	}
}
/*
创世块
 */
func GenesisBlock() *Block {
	return NewBlock("创世块", []byte{})
}

/*
添加区块到区块链中
*/
func (bc *BlockChain) AddBlock(data string) {
	db := bc.BoltDB
	lashHash:=bc.lastHash
	//创建当前区块
	block := NewBlock(data, lashHash)
	db.Update(func(tx *bolt.Tx) error {
		//查找抽屉
		bucket:=tx.Bucket([]byte("blockBucket"))
		if bucket==nil{
			log.Panic("不应该为空")
		}else{
			//有抽屉,存入block
			bucket.Put(block.CurrentHash,block.Serialize())
			bucket.Put([]byte("lastHashKey"),block.CurrentHash)

			//更新内存中的lastHash
			bc.lastHash=block.CurrentHash

		}

		return nil
	})


}
func (bc *BlockChain) Printchain() {

	bc.BoltDB.View(func(tx *bolt.Tx) error {
		// Assume bucket exists and has keys
		b := tx.Bucket([]byte("blockBucket"))

		//从第一个key-> value 进行遍历，到最后一个固定的key时直接返回
		b.ForEach(func(k, v []byte) error {
			if bytes.Equal(k, []byte("lastHashKey")) {
				return nil
			}

			block := DeSerialize(v)
			//fmt.Printf("key=%x, value=%s\n", k, v)
			fmt.Printf("===========================\n\n")
			fmt.Printf("版本号: %d\n", block.Version)
			fmt.Printf("前区块哈希值: %x\n", block.PrevHash)
			fmt.Printf("梅克尔根: %x\n", block.MerkleRoot)
			fmt.Printf("时间戳: %d\n", block.TimeStamp)
			fmt.Printf("难度值(随便写的）: %d\n", block.Difficulty)
			fmt.Printf("随机数 : %d\n", block.Nonce)
			fmt.Printf("当前区块哈希值: %x\n", block.CurrentHash)
			fmt.Printf("区块数据 :%s\n", block.Data)
			return nil
		})
		return nil
	})
}